package org.example.domain.strategy.service.rule.Tree.Engine;

import org.example.domain.strategy.model.valobj.*;
import org.example.domain.strategy.service.rule.Tree.Engine.factory.DefaultTreeFactory;
import org.example.domain.strategy.service.rule.Tree.Node.ITreeNode;
import org.example.types.exception.AppException;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


public class DecisionTreeEngine implements IDecisionTreeEngine{

    Map<String, ITreeNode> treeNodeMap;

    RuleTreeVO ruleTreeVO;

    public DecisionTreeEngine(Map<String, ITreeNode> treeNodeMap, RuleTreeVO ruleTreeVO) {
        this.ruleTreeVO = ruleTreeVO;
        this.treeNodeMap = treeNodeMap;
    }

    @Override
    public DefaultTreeFactory.StrategyAwardVO pocess(String userId, Long strategyId, String awardId) {
        String treeRoot = ruleTreeVO.getRootNodeKey();
        Map<String , RuleTreeNodeVO>  ruleTreeNodeVOMap = ruleTreeVO.getRuleTreeNodeVOMap();

        DefaultTreeFactory.StrategyAwardVO strategyAwardData = null;
        String nextNodeStr = treeRoot;
        while(nextNodeStr!= null  ) {//这里设置了为空则跳出,说明要在后面的函数中设置相应的null值

            //根据字符串在map中获取决策节点和决策辅助类VO
            ITreeNode nextNode = treeNodeMap.get(nextNodeStr); //真实的处理类
            RuleTreeNodeVO ruleTreeNodeVO = ruleTreeNodeVOMap.get(nextNodeStr);// 决策辅助类VO:用来寻找下一个逻辑的类
            String ruleValue = ruleTreeNodeVO.getRuleValue();

            //执行处理逻辑
            DefaultTreeFactory.TreeActionEntity treeActionEntity = nextNode.logic(userId, strategyId, awardId,ruleValue); //真实处理类进行逻辑处理并返回结果
            RuleLimitValueVO ruleLimitValueVO = treeActionEntity.getRuleLimitValueVO(); //从结果中获取判断逻辑走向的判别因子
            strategyAwardData = treeActionEntity.getStrategyAwardData(); //从结果中获取处理后的结果数据

            //获取下一个节点
            nextNodeStr = nextNode(ruleLimitValueVO.getCode(), ruleTreeNodeVO.getRuleTreeNodeLineVOList());//根据判别因子和寻找逻辑的类来判断下一个节点

        }
        return strategyAwardData;
    }

    @Override
    public DefaultTreeFactory.StrategyAwardVO pocess(String userId, Long strategyId, String awardId, Date endDateTime) {
        String treeRoot = ruleTreeVO.getRootNodeKey();
        Map<String , RuleTreeNodeVO>  ruleTreeNodeVOMap = ruleTreeVO.getRuleTreeNodeVOMap();

        DefaultTreeFactory.StrategyAwardVO strategyAwardData = null;
        String nextNodeStr = treeRoot;
        while(nextNodeStr!= null  ) {//这里设置了为空则跳出,说明要在后面的函数中设置相应的null值

            //根据字符串在map中获取决策节点和决策辅助类VO
            ITreeNode nextNode = treeNodeMap.get(nextNodeStr); //真实的处理类
            RuleTreeNodeVO ruleTreeNodeVO = ruleTreeNodeVOMap.get(nextNodeStr);// 决策辅助类VO:用来寻找下一个逻辑的类
            String ruleValue = ruleTreeNodeVO.getRuleValue();

            //执行处理逻辑
            DefaultTreeFactory.TreeActionEntity treeActionEntity = nextNode.logic(userId, strategyId, awardId,ruleValue,endDateTime); //真实处理类进行逻辑处理并返回结果
            RuleLimitValueVO ruleLimitValueVO = treeActionEntity.getRuleLimitValueVO(); //从结果中获取判断逻辑走向的判别因子
            strategyAwardData = treeActionEntity.getStrategyAwardData(); //从结果中获取处理后的结果数据

            //获取下一个节点
            nextNodeStr = nextNode(ruleLimitValueVO.getCode(), ruleTreeNodeVO.getRuleTreeNodeLineVOList());//根据判别因子和寻找逻辑的类来判断下一个节点

        }
        return strategyAwardData;
    }

    /**
     *  获取当前节点的下一个节点的key
     *  matterValue是这个节点的判断值,ruleTreeNodeLineVOList是这个节点的所有走向,以此来进行匹配
     * @param matterValue
     * @param ruleTreeNodeLineVOList
     * @return
     */
    private String nextNode(String matterValue, List<RuleTreeNodeLineVO> ruleTreeNodeLineVOList) {
        if (null == ruleTreeNodeLineVOList || ruleTreeNodeLineVOList.isEmpty()) return null; //ruleTreeNodeLineVOList为空说明后面没有节点了,即是叶子节点了
        for (RuleTreeNodeLineVO  ruleTreeNodeLineVO :ruleTreeNodeLineVOList){//对每个分支进行判断

            if (decisionLogic(matterValue, ruleTreeNodeLineVO)) {
                return ruleTreeNodeLineVO.getToNodeKey();
            }
        }
        return null;
    }

    /**
     *
     * @param matterValue
     * @param ruleTreeNodeLineVO
     * @return
     */
    private boolean decisionLogic(String matterValue, RuleTreeNodeLineVO ruleTreeNodeLineVO) {
        String limitValue = ruleTreeNodeLineVO.getLimitValue().getCode();
        RuleLimitTypeVO ruleLimitTypeVO = ruleTreeNodeLineVO.getLimitType();
        switch (ruleLimitTypeVO){
            case EQUAL:
                return limitValue.equals(matterValue);
                // 以下规则暂时不需要实现
            case GT:
            case LT:
            case GE:
            case LE:
            default:
                return false;
        }

    }
}
